require('glon');

function GPM.SendPM(to, from, m, both)
	if hook.Call("OnPrivateMessage", GPM, to, from, m) then
		umsg.Start( "NewMessage", from )
			umsg.Entity( to );
			if m then
				umsg.String( m );
			end
		umsg.End( );
		if both then
			umsg.Start( "IncommingPM", to )
				umsg.Entity( from );
				if m then
					umsg.String( m );
				end
			umsg.End( );
		end
	end
end

function GPM.PlayerBlock(blockee, blocker, reason)
	if hook.Call("OnPlayerBlock", GPM, blocker, blockee, reason) then
		if blocker.GPMBlocks[blockee:SteamID()] then
			blocker:ChatPrint("[GPM] "..blockee:Nick().." has already been blocked.");
			return;
		end
		blocker.GPMBlocks[blockee:SteamID()] = reason or "";
		blocker:ChatPrint("[GPM] You have blocked "..blockee:Nick()..".");
		GPM.SaveBlockTable(blocker);
	end
end

function GPM.PlayerUnblock(unblockee, unblocker)
	if hook.Call("OnPlayerUnBlock", GPM, unblocker, unblockee) then
		if unblocker.GPMBlocks[unblockee:SteamID()] then
			unblocker.GPMBlocks[unblockee:SteamID()] = nil;
			unblocker:ChatPrint("[GPM] "..unblockee:Nick().." has been unblocked.");
			GPM.SaveBlockTable(unblocker);
			return;
		end
		unblocker:ChatPrint("[GPM] "..unblockee:Nick().." isn't blocked.");
	end
end

function GPM:OnPlayerBlock(ply, victom, reason)
	-- hook me
	return true;
end

function GPM:OnPlayerUnBlock(ply, victom)
	-- hook me
	return true;
end

function GPM:OnPrivateMessage(to, from, message)
	-- hook me
	if to.GPMBlocks[from:SteamID()] then
		if to.GPMBlocks[from:SteamID()] == "" then
			from:ChatPrint("[GPM] You have been blocked by "..to:Nick()..".");
		else
			from:ChatPrint("[GPM] You have been blocked by "..to:Nick()..". Reason: "..to.GPMBlocks[from:SteamID()]..".");
		end
		return false;
	end
	if from.GPMBlocks[to:SteamID()] then
		GPM.PlayerUnblock(to, from);
	end
	return true;
end

function GPM.SaveBlockTable(ply)
	local tab = ply.GPMBlocks;
	local savestr = glon.encode(tab);
	file.Write("GPM/Player Data/"..ply:SteamID():gsub("[:%.]", "_")..".txt", savestr);
end

function GPM.LoadBlockTable(ply)
	local loadstr = file.Read("GPM/Player Data/"..ply:SteamID():gsub("[:%.]", "_")..".txt");
	if loadstr and loadstr != "" then
		local tab = glon.decode(loadstr);
		ply.GPMBlocks = tab;
	else
		ply.GPMBlocks = {};
	end
end

hook.Add( "PlayerSay", "GPM.Hooks.Chat", function( ply, text )
	local tab = string.Explode( " ", text );
	if tab[1] == "/pm" then
		local ptext = tab[2];
		if !ptext then
			ply:ChatPrint("[GPM] /pm <name>");
			return ""
		end
		local found = player.FindByName(ptext);
		if ( #found > 1 ) then
			ply:ChatPrint("[GPM] More than one player found, please enter more of the name");
		elseif ( #found == 0 ) then
			ply:ChatPrint("[GPM] Player not found");
		else
			GPM.SendPM(found[1], ply, nil, false);
		end
		return "";
	elseif tab[1] == "/block" then
		local ptext = tab[2];
		if !ptext then
			ply:ChatPrint("[GPM] /block <name>");
			return "";
		end
		local found = player.FindByName(ptext);
		if ( #found > 1 ) then
			ply:ChatPrint("[GPM] More than one player found, please enter more of the name");
		elseif ( #found == 0 ) then
			ply:ChatPrint("[GPM] Player not found");
		else
			GPM.PlayerBlock(found[1], ply, table.concat(tab, " ", 3, #tab));
		end
		return "";
	elseif tab[1] == "/unblock" then
		local ptext = tab[2];
		if !ptext then
			ply:ChatPrint("[GPM] /unblock <name>");
			return "";
		end
		local found = player.FindByName(ptext);
		if ( #found > 1 ) then
			ply:ChatPrint("[GPM] More than one player found, please enter more of the name");
		elseif ( #found == 0 ) then
			ply:ChatPrint("[GPM] Player not found");
		else
			GPM.PlayerUnblock(found[1], ply);
		end
		return "";
	end
end );

hook.Add("PlayerInitialSpawn", "GPM.Hooks.PlayerInitialSpawn", function(ply)
	GPM.LoadBlockTable(ply);
end);

concommand.Add("SendPM", function(ply, cmd, args)
	local Index = args[1];
	if Index then
		local text = args[2];
		local to = ents.GetByIndex(tonumber(Index));
		if to then
			local from = ply;
			GPM.SendPM( to, from, text, true );
		end
	end
end);

concommand.Add("ToggleBlock", function(ply, cmd, args)
	local Index = args[1];
	if Index then
		local p = ents.GetByIndex(tonumber(Index));
		if p then
			if ply.GPMBlocks[p:SteamID()] then
				GPM.PlayerUnblock(p, ply);
			else
				GPM.PlayerBlock(p, ply);
			end
		end
	end
end);

function player.FindByName(name)
	local found = { };
	for k, v in ipairs( player.GetAll( ) ) do
		if string.match( string.lower( v:Nick( ) ), string.lower( name ) ) then
			table.insert( found, v );
		end
	end
	return found;
end